package projeto;

import grafoS.GraphList;
import grafoS.Graph;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.scene.control.TabPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

/**
 * Gcol is a program to help users to learn a little about graph coloring, in
 * this software, you can learn some coloring algorithms, and add your own
 * algorithm for coloring.You can also learn BFS and DFS search. This tool, also
 * support the .col format from DIMACS (Center for Discrete Mathematics and
 * Theoretical Computer Science), so you can import a big graph and use all the
 * algorithms. Copyright (C) <2015> Clóvis Daniel Souza Silva, Samuel Silva de
 * Souza, Professor Leonardo Sampaio Rocha.
 * 
* This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
* This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
* You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 * contact: projetoGrafos@gmail.com
 */
/**
 *
 * @author Daniel
 * @author Samuel
 */
/**
 *
 * This class, extends thread, because we'll need a thread to use sleep when
 * coloring, This way, we can see the step-by-step BFS(in portuguese Busca Por
 * Largura). In this class, we have a huge parameters because we'll use some
 * elements of the interface, like circles, text area, tab pane, we'll also need
 * the graph from the class Graph, the int v to know where to start the search,
 * and the arrayList where we put the string for the console.
 */
public class BuscaLargura extends Thread {

    private int tabExecuntando;
    private String textoAnterior;
    private Graph matrizAdjacencia;
    private TabPane tabPane;
    private ArrayList<String> stringConsole;
    private ArrayList<Integer> permissaoTab;
    private ArrayList<ArrayList<Circle>> vertices;
    private javafx.scene.control.TextArea console;
    private ArrayList<Integer> nVertices;
    private int t;

    @Override
    public void run() {
        tabExecuntando = tabPane.getSelectionModel().getSelectedIndex();
        textoAnterior = stringConsole.get(tabExecuntando);
        if (vertice > 0) {
            BFS(vertice);
        }
    }
    private int vertice;

    /**
     * This is the constructor, where we recive all the parameters from the
     * "Controle" class
     *
     * @param v represents the index of the vertex.
     * @param mA represents the adjacency matrix.
     * @param tP represents the current tab.
     * @param sC keep the record of the tasks in console.
     * @param pT the valor of permission, which is used to make exceptions for
     * each function.
     * @param listaVertices list with all the circles in the canvas, we'll use
     * to make a visible step-by-step of BFS.
     * @param c we'll receive the console to print the visit order.
     * @param nV keep the number of vertices.
     * @param aba the integer that represents the index of the current pane.
     */
    public BuscaLargura(int v, Graph mA, TabPane tP, ArrayList<String> sC,
            ArrayList<Integer> pT, ArrayList<ArrayList<Circle>> listaVertices,
            javafx.scene.control.TextArea c, ArrayList<Integer> nV, int aba) {
        vertice = v + 1;
        matrizAdjacencia = mA;
        tabPane = tP;
        stringConsole = sC;
        permissaoTab = pT;
        vertices = listaVertices;
        console = c;
        nVertices = nV;
        t = aba;

    }

    /**
     * This is the method for BFS, in this method we use a vector fila as a
     * queue, but instead of pull the vector, we increment iF whose it's the
     * head of the queue, we also have the integer fF whose it's the tail of the
     * queue. The collor usage works the same way as "BuscaProfundidade" on DFS.
     * It's also important to say that we'll normally use ver-1 , because we're
     * working with vector.
     *
     * @param ver index of the vertex.
     */
    public void BFS(int ver) {

        int[][] Grafo = matrizAdjacencia.getGrafo();
        int fila[] = new int[nVertices.get(t)];
        int iF = 0;//Inicio Fila
        int fF = 0;//Final Fila
        String textoFila = "\nVisit Order: ", aux = "";
        matrizAdjacencia.toWhite();
        char[] cor = matrizAdjacencia.getCor();
        cor[ver - 1] = 'C';
        colorir(ver - 1);
        try {
            if (vertices != null) {
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        fila[iF] = ver - 1;
        textoFila += aux.valueOf(fila[iF] + 1);
        fF++;
        for (int i = 0; i < fF; i++) {
            for (int j = 0; j < Grafo.length; j++) {
                if (Grafo[fila[iF]][j] == 1 && cor[j] == 'B') {

                    cor[j] = 'C';
                    colorir(j);
                    try {
                        if (vertices != null) {
                            Thread.sleep(1000);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    fila[fF] = j;
                    textoFila += "; " + aux.valueOf(fila[fF] + 1);
                    imprimir(textoFila, textoAnterior);
                    console.end();
                    fF++;
                }

            }
            cor[fila[iF]] = 'P';
            recolorir(fila[iF], tabExecuntando);
            try {
                if (vertices != null) {
                    Thread.sleep(1500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            iF++;
        }
        if (fF == 1) {
            imprimir(textoFila, textoAnterior);
            console.end();
        }
        try {
            if (vertices != null) {
                Thread.sleep(3000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Platform.runLater(() -> toWhite());
        permissaoTab.set(tabExecuntando, 0);
        Platform.runLater(() -> tabPane.getTabs().get(tabExecuntando).getContent().setDisable(false));
        if (tabPane.getSelectionModel().getSelectedIndex() == tabExecuntando) {
            Platform.runLater(() -> console.appendText("\n"));
        }
        stringConsole.set(tabExecuntando, stringConsole.get(t) + "\n");
    }

    /**
     * method to vertex go beige.
     *
     * @param a the index of the vertex.
     */
    public void colorir(int a) {
        if (vertices != null) {
            Platform.runLater(() -> this.vertices.get(tabExecuntando).get(a).setFill(Color.KHAKI));
        }
    }

    /**
     * method to the vertex go crimson.
     *
     * @param a the index of the vertex.
     * @param tabExecutando receive the index of the current tab.
     */
    public void recolorir(int a, int tabExecutando) {
        if (vertices != null) {
            Platform.runLater(() -> this.vertices.get(tabExecutando).get(a).setFill(Color.color(0.9, 0.1, 0.1)));
        }
    }

    /**
     * method to all vertex go white.
     */
    public void toWhite() {
        if (vertices != null) {
            for (int i = 0; i < vertices.get(tabExecuntando).size(); i++) {
                vertices.get(tabExecuntando).get(i).setFill(Color.WHITE);
            }
        }
    }

    /**
     * method to print in the console the BFS.
     *
     * @param textoFila append text to add in console.
     * @param textoAnterior keep the previous text in the console.
     */
    public void imprimir(String textoFila, String textoAnterior) {
        if (tabPane.getTabs().get(tabExecuntando).isSelected()) {
            Platform.runLater(() -> console.setText(textoAnterior + textoFila + "\n"));
            console.end();
            stringConsole.set(tabExecuntando, textoAnterior + textoFila + "\n");
        } else {
            stringConsole.set(tabExecuntando, textoAnterior + textoFila + "\n");
        }
    }

}
